import traceback
import ujson
from typing import Optional

from src.model import Category, Entry, EntryContent, db
from src.schemas.response import ResponseModel


def CRUDWrapper(func):
    def _wrappedFunc(*args, **kwargs):
        try:
            with db:
                return func(*args, **kwargs)
        except Exception as e:
            print(traceback.format_exc())
            return ResponseModel.ReturnException(e)

    return _wrappedFunc


def _selectAllCategories(lang: str) -> list:
    def getName(item):
        dataStr = item.translated_name
        try:
            data = ujson.loads(dataStr)
            translatedName = data.get(lang)
            return translatedName if translatedName else item.name
        except Exception as e:
            return item.name

    query = Category.select()
    return [{
        "cid": item.cid,
        "name": item.name if lang == "zh-CN" else getName(item),
        "parent_cid": item.parent_cid
    } for item in query]


def _selectEntries(cid: int, lang: str) -> list:
    # SELECT * FROM entry_content ec LEFT JOIN entry e ON e.eid = ec.eid;
    query = EntryContent \
        .select() \
        .join(Entry, on=(Entry.eid == EntryContent.eid)) \
        .where((Entry.cid == cid) & (EntryContent.lang == lang))
    return [{
        "eid": item.eid.eid,
        "cid": cid,
        "title": item.title,
        "content": item.content,
        "updated": item.updated,
        "created": item.created
    } for item in query]


def _selectEntry(eid: int, lang: str) -> Optional[dict]:
    query = EntryContent.select().join(Entry, on=(Entry.eid == EntryContent.eid)).where(
        (Entry.eid == eid) & (EntryContent.lang == lang))
    if query:
        res = query.first()
        return {
            "eid": res.eid.eid,
            "cid": res.eid.cid.cid,
            "title": res.title,
            "content": res.content,
            "updated": res.updated,
            "created": res.created
        }
    else:
        return None


def _selectSearchKeyword(keyword: str, lang: str) -> list:
    # SELECT * FROM `entry_content` ec LEFT JOIN entry e ON ec.eid = e.eid WHERE (title LIKE '%向晚%' OR content LIKE '%向晚%') and lang = 'zh-CN';
    query = EntryContent \
        .select() \
        .join(Entry, on=(EntryContent.eid == Entry.eid)) \
        .where((EntryContent.title ** "%{}%".format(keyword)) | (EntryContent.content ** "%{}%".format(keyword))) \
        .where(EntryContent.lang == lang)
    return [{
        "eid": item.eid.eid,
        "cid": item.eid.cid.cid,
        "title": item.title,
        "content": item.content,
        "updated": item.updated,
        "created": item.created
    } for item in query]


@CRUDWrapper
def selectEntries(cid: int, lang: str) -> ResponseModel:
    return ResponseModel.ReturnSuccess(_selectEntries(cid, lang))


@CRUDWrapper
def selectEntry(eid: int, lang: str) -> ResponseModel:
    res = _selectEntry(eid, lang)
    if res:
        return ResponseModel.ReturnSuccess(res)
    else:
        return ResponseModel.ReturnFailed("没有结果捏~")


@CRUDWrapper
def selectAllCategories(lang: str) -> ResponseModel:
    return ResponseModel.ReturnSuccess(_selectAllCategories(lang))


@CRUDWrapper
def selectSearchKeyword(keyword: str, lang: str) -> ResponseModel:
    return ResponseModel.ReturnSuccess(_selectSearchKeyword(keyword, lang))
